﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ODESolver
{
    /// <summary>
    /// Система диффуров
    /// </summary>
    /// <param name="N">номер уравнения, правая часть которого возвращается</param>
    /// <param name="t">время системы</param>
    /// <param name="x">вектор состояния</param>
    /// <param name="par">параметры системы</param>
    /// <returns>правая часть</returns>
    public delegate double ODESys(int N, double t, double[] x, double[] par);

    /// <summary>
    /// Список методов интегрирования
    /// </summary>
    public enum IntegrationMethod
    {
        /// <summary>
        /// Метод рунге-кутты 4ого порядка
        /// </summary>
        RungeKutta4,
        /// <summary>
        /// Метод бутчера (рк 6ого порядка)
        /// </summary>
        Butcher,
        /// <summary>
        /// Метод рк5-4(пока без адаптаций)
        /// </summary>
        Fehlberg
    }

    /// <summary>
    /// Класс для интегрирования систем ОДУ
    /// </summary>
    public static partial class  OdeSolver
    {
        /// <summary>
        /// "Решатель ОДУ" 
        /// </summary>
        /// <param name="f">система, которую решает "Решатель ОДУ" </param>
        /// <param name="T">время интегрирования</param>
        /// <param name="step">шаг интегрирования</param>
        /// <param name="init">начальные условия</param>
        /// <param name="arg">параметры системы уравнений</param>
        /// <param name="meth">метод интегрирования</param>
        /// <returns></returns>
        static public double[] SolveOnTime(ODESys f, double T, double step, double[] init, double[] arg, IntegrationMethod meth)
        {
            switch (meth)
            {
              //  case IntegrationMethod.RungeKuttaCashCarp:
              //      return CashCarpOnTime(f, T, (int)(T / step), init, arg, 1e-10);
                case IntegrationMethod.RungeKutta4:
                    return RungeKuttaOnTime(f, T, step, init, arg);
                case IntegrationMethod.Butcher:
                    return ButcherOnTime(f, T, step, init, arg);
                case IntegrationMethod.Fehlberg:
                    return FehlbergOnTime(f, T, step, init, arg);

            }
            return null;
        }


        /// <summary>
        /// "Решатель ОДУ по шагам" 
        /// </summary>
        /// <param name="f">система, которую решает "Решатель ОДУ" </param>
        /// <param name="T">ВРЕМЯ СИСТЕМЫ, А НЕ ИНТЕРВАЛ НА КОТОРОМ ИНТЕГРИРУЮТ!</param>
        /// <param name="step">шаг интегрирования</param>
        /// <param name="init">начальные условия</param>
        /// <param name="arg">параметры системы уравнений</param>
        /// <param name="meth">метод интегрирования</param>
        /// <returns></returns>
        static public double[] OneStep(ODESys f, double t, double step, double[] init, double[] arg, IntegrationMethod meth)
        {
            switch (meth)
            {
                case IntegrationMethod.RungeKutta4:
                    return RungeKuttaOneStep(f, t, step, init, arg);
                case IntegrationMethod.Butcher:
                    return ButcherOneStep(f, t, step, init, arg);
                case IntegrationMethod.Fehlberg:
                    return FehlbergOneStep(f, t, step, init, arg);
            }
            return null;
        }

        /// <summary>
        /// Возвращает траекторию системы
        /// </summary>
        /// <param name="f"></param>
        /// <param name="T"></param>
        /// <param name="step"></param>
        /// <param name="init"></param>
        /// <param name="arg"></param>
        /// <param name="meth"></param>
        /// <returns></returns>
        static public double[,] Trajectory(ODESys f, double T, double step, double[] init, double[] arg, IntegrationMethod meth)
        {

            switch (meth)
            {
                // case IntegrationMethod.RungeKuttaCashCarp:
                //     return null;
                case IntegrationMethod.RungeKutta4:
                    return RungeKuttaTrajectory(f, T, step, init, arg);
                case IntegrationMethod.Butcher:
                    return ButcherTrajectory(f, T, step, init, arg);
                case IntegrationMethod.Fehlberg:
                    return FehlbergTrajectory(f, T, step, init, arg);
            }
            return null;

        }
    }
}
